/**
 * 浏览器存储适配器
 * 简化版本，基于 IndexedDB
 */

import { BaseStorageAdapter } from './BaseStorageAdapter';
import { IStorageConfig, IUploadOptions, IUploadResult } from './interfaces';

/**
 * 浏览器存储适配器实现
 */
export class BrowserStorageAdapter extends BaseStorageAdapter {
  private db: IDBDatabase | null = null;
  private readonly dbName: string;
  private readonly storeName = 'files';
  private readonly maxSize: number;

  constructor(config: IStorageConfig = {}) {
    super('BrowserStorage', config);
    this.dbName = config.browser?.dbName || 'contentflow_storage';
    this.maxSize = config.browser?.maxSize || 100 * 1024 * 1024; // 100MB
  }

  async initialize(): Promise<void> {
    try {
      this.db = await this.openDatabase();
      this.markAsInitialized();
      this.logger.info('Browser storage adapter initialized', {
        dbName: this.dbName,
        maxSize: this.maxSize
      });
    } catch (error) {
      this.logger.error('Failed to initialize browser storage', error as Error);
      throw new Error(`Failed to initialize browser storage: ${(error as Error).message}`);
    }
  }

  async upload(file: File | Blob | Buffer, options: IUploadOptions = {}): Promise<IUploadResult> {
    this.ensureInitialized();

    const id = this.generateFileId(options.filename);
    const filename = options.filename || 'file';
    const size = this.getFileSize(file);
    const mimeType = this.getMimeType(file);
    const uploadedAt = new Date();

    // 检查存储空间
    await this.checkStorageSpace(size);

    // 获取图片尺寸
    let dimensions: { width: number; height: number } | undefined;
    if (file instanceof File || file instanceof Blob) {
      dimensions = await this.getImageDimensions(file);
    }

    // 转换为 ArrayBuffer 存储
    const arrayBuffer = await this.fileToArrayBuffer(file);

    // 存储到 IndexedDB
    const fileData = {
      id,
      filename,
      size,
      mimeType,
      uploadedAt,
      dimensions,
      data: arrayBuffer
    };

    await this.storeFile(fileData);

    // 生成本地 URL
    const url = this.generateLocalUrl(id);

    return {
      id,
      url,
      filename,
      size,
      mimeType,
      uploadedAt,
      dimensions
    };
  }

  async delete(id: string): Promise<void> {
    this.ensureInitialized();
    
    const transaction = this.db!.transaction([this.storeName], 'readwrite');
    const store = transaction.objectStore(this.storeName);
    
    return new Promise((resolve, reject) => {
      const request = store.delete(id);
      request.onsuccess = () => resolve();
      request.onerror = () => reject(new Error(`Failed to delete file: ${id}`));
    });
  }

  async exists(id: string): Promise<boolean> {
    this.ensureInitialized();
    
    const transaction = this.db!.transaction([this.storeName], 'readonly');
    const store = transaction.objectStore(this.storeName);
    
    return new Promise((resolve, reject) => {
      const request = store.count(id);
      request.onsuccess = () => resolve(request.result > 0);
      request.onerror = () => reject(new Error(`Failed to check file existence: ${id}`));
    });
  }

  async getInfo(id: string): Promise<IUploadResult> {
    this.ensureInitialized();
    
    const transaction = this.db!.transaction([this.storeName], 'readonly');
    const store = transaction.objectStore(this.storeName);
    
    return new Promise((resolve, reject) => {
      const request = store.get(id);
      request.onsuccess = () => {
        const result = request.result;
        if (!result) {
          reject(new Error(`File not found: ${id}`));
          return;
        }
        
        resolve({
          id: result.id,
          url: this.generateLocalUrl(id),
          filename: result.filename,
          size: result.size,
          mimeType: result.mimeType,
          uploadedAt: result.uploadedAt,
          dimensions: result.dimensions
        });
      };
      request.onerror = () => reject(new Error(`Failed to get file info: ${id}`));
    });
  }

  async destroy(): Promise<void> {
    if (this.db) {
      this.db.close();
      this.db = null;
    }
    this._initialized = false;
  }

  /**
   * 打开数据库
   */
  private openDatabase(): Promise<IDBDatabase> {
    return new Promise((resolve, reject) => {
      const request = indexedDB.open(this.dbName, 1);
      
      request.onerror = () => reject(new Error('Failed to open IndexedDB'));
      request.onsuccess = () => resolve(request.result);
      
      request.onupgradeneeded = (event) => {
        const db = (event.target as IDBOpenDBRequest).result;
        if (!db.objectStoreNames.contains(this.storeName)) {
          db.createObjectStore(this.storeName, { keyPath: 'id' });
        }
      };
    });
  }

  /**
   * 检查存储空间
   */
  private async checkStorageSpace(fileSize: number): Promise<void> {
    // 简单的空间检查，实际项目中可以更精确
    if (fileSize > this.maxSize) {
      throw new Error(`File size exceeds maximum allowed size: ${this.maxSize} bytes`);
    }
  }

  /**
   * 文件转 ArrayBuffer
   */
  private async fileToArrayBuffer(file: File | Blob | Buffer): Promise<ArrayBuffer> {
    if (Buffer.isBuffer(file)) {
      return file.buffer.slice(file.byteOffset, file.byteOffset + file.byteLength);
    }
    
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = () => resolve(reader.result as ArrayBuffer);
      reader.onerror = () => reject(new Error('Failed to read file'));
      reader.readAsArrayBuffer(file);
    });
  }

  /**
   * 存储文件到 IndexedDB
   */
  private storeFile(fileData: any): Promise<void> {
    const transaction = this.db!.transaction([this.storeName], 'readwrite');
    const store = transaction.objectStore(this.storeName);
    
    return new Promise((resolve, reject) => {
      const request = store.put(fileData);
      request.onsuccess = () => resolve();
      request.onerror = () => reject(new Error('Failed to store file'));
    });
  }

  /**
   * 生成本地访问 URL
   */
  private generateLocalUrl(id: string): string {
    return `indexeddb://${this.dbName}/${this.storeName}/${id}`;
  }
}
